/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package com.inspur.edp.metadata.rtcustomization.servermanager;

import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.lcm.metadata.api.entity.I18nResource;
import com.inspur.edp.lcm.metadata.api.entity.Metadata4Ref;
import com.inspur.edp.lcm.metadata.api.entity.MetadataDto;
import com.inspur.edp.lcm.metadata.api.entity.MetadataPackage;
import com.inspur.edp.lcm.metadata.api.entity.ProcessMode;
import com.inspur.edp.lcm.metadata.cache.MetadataDistCacheManager;
import com.inspur.edp.lcm.metadata.cache.MetadataRtDistCache;
import com.inspur.edp.lcm.metadata.cache.RtCacheHandler;
import com.inspur.edp.lcm.metadata.common.MetadataDtoConverter;
import com.inspur.edp.lcm.metadata.common.MetadataSerializer;
import com.inspur.edp.lcm.metadata.common.ServiceUtils;
import com.inspur.edp.lcm.metadata.common.configuration.I18nManagerHelper;
import com.inspur.edp.lcm.metadata.common.context.RuntimeContext;
import com.inspur.edp.lcm.metadata.spi.MetadataI18nService;
import com.inspur.edp.lcm.metadata.spi.event.MdPkgChangedArgs;
import com.inspur.edp.metadata.rtcustomization.api.entity.GspMdCustomContent;
import com.inspur.edp.metadata.rtcustomization.api.entity.GspMdRtContent;
import com.inspur.edp.metadata.rtcustomization.api.entity.MetadataFilter;
import com.inspur.edp.metadata.rtcustomization.api.entity.MetadataStringDto;
import com.inspur.edp.metadata.rtcustomization.api.entity.SourceTypeEnum;
import com.inspur.edp.metadata.rtcustomization.common.EnvironmentContext;
import com.inspur.edp.metadata.rtcustomization.common.event.MetadataRtEventBroker;
import com.inspur.edp.metadata.rtcustomization.inner.api.I18nResourceRTService;
import com.inspur.edp.metadata.rtcustomization.inner.api.utils.I18nResourceRTUtils;
import com.inspur.edp.metadata.rtcustomization.servermanager.event.MdPkgChangedEventBroker;
import com.inspur.edp.metadata.rtcustomization.servermanager.repository.GeneratedRepoService;
import com.inspur.edp.metadata.rtcustomization.servermanager.repository.MdRtRepoService;
import com.inspur.edp.metadata.rtcustomization.spi.event.MetadataRtEventArgs;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import io.iec.edp.caf.i18n.api.LanguageService;
import io.iec.edp.caf.i18n.entity.EcpLanguage;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

@Slf4j
public abstract class AbstractMetadataService {

    public MdRtRepoService mdRtRepoService;
    public GeneratedRepoService generatedRepoService;
    private MetadataRtEventBroker metadataRtEventBroker;

    private MetadataRtEventBroker getMetadataRtEventBroker() {
        if (metadataRtEventBroker == null) {
            metadataRtEventBroker = SpringBeanUtils.getBean(MetadataRtEventBroker.class);
        }
        return metadataRtEventBroker;
    }

    public void saveMetadataToCache(String metadataId) {
        getMetadata(metadataId);
    }

    public void saveMetadataWithoutI18nToCache(String metadataId) {
        // 非国际化
        getMetadataWithoutI18n(metadataId);
    }

    public MetadataDto getMetadataDto(String metadataId) {
        GspMetadata metadata = getMetadata(metadataId);
        return MetadataDtoConverter.asDto(metadata);
    }

    public GspMetadata getMetadata(String metadataId) {
        GspMetadata i18nMetadata = getMetadataFromCache(metadataId, true);
        if (i18nMetadata != null) {
            putMetadataToCache(metadataId, i18nMetadata, true);
            return i18nMetadata;
        }

        // 从数据库中获取元数据
        GspMetadata metadata = getMetadataFromDb(metadataId);
        if (metadata == null) {
            return null;
        }

        i18nMetadata = getI18nMetadata(metadata, RuntimeContext.getLanguage());
        if (i18nMetadata != null) {
            fireMetadataAchievedEvent(metadata);

            putMetadataToCache(metadataId, metadata, true);
        }

        return i18nMetadata;
    }

    public MetadataStringDto getMetadataStringDto(String metadataId) {
        // 获取包中的元数据
        GspMdRtContent gspMdRtContent = mdRtRepoService.findByMetadataIdAndSourceType(metadataId, SourceTypeEnum.MDPKG);
        if (gspMdRtContent != null) {
            return new MetadataStringDto(gspMdRtContent.getContent(), gspMdRtContent.getLastChangedOn().toString());
        }

        // 获取idp表中的元数据
        GspMdCustomContent gspMdCustomContent = generatedRepoService.findByMetadataId(metadataId);
        if (gspMdCustomContent != null) {
            return new MetadataStringDto(generatedRepoService.buildMetadataString(gspMdCustomContent), gspMdCustomContent.getLastChangedOn().toString());
        }

        // 获取运行时定制过程中的元数据，或者运行时定制发布的元数据
        return getCustomizedMetadataStringDto(metadataId);
    }

    protected MetadataStringDto getCustomizedMetadataStringDto(String metadataId) {
        return null;
    }

    public GspMetadata getMetadataWithoutI18n(String metadataId) {
        // 非国际化
        GspMetadata metadata = getMetadataFromCache(metadataId, false);
        if (metadata != null) {
            putMetadataToCache(metadataId, metadata, false);
            return metadata;
        }

        metadata = getMetadataFromDb(metadataId);
        if (metadata == null) {
            return null;
        }

        fireMetadataAchievedEvent(metadata);

        putMetadataToCache(metadataId, metadata, false);

        return metadata;
    }

    /**
     * 获取GspMdCustomContent表中Id对应的元数据
     * @param metadataId 查询元数据Id
     * @return 元数据
     */
    public GspMetadata getGenerateMetadataWithoutI18n(String metadataId) {
        return generatedRepoService.getMetadata(metadataId);
    }

    public GspMetadata getMetadataFromMdpkg(String mdpkgPath, String fileName) {
        Map<String, String> metadataMap = ServiceUtils.readCompressedFile(new File(mdpkgPath), fileName);
        if (CollectionUtils.isEmpty(metadataMap)) {
            log.info(String.format("无法从元数据包{%s}中获取元数据{%s}", mdpkgPath, fileName));
            return null;
        }
        GspMetadata metadata = new MetadataSerializer().deserialize(metadataMap.get(fileName), GspMetadata.class);
        return metadata;
    }

    public List<Metadata4Ref> getMetadataListByFilters(List<MetadataFilter> metadataFilters) {
        List<Metadata4Ref> metadataList = new ArrayList<>();
        for (MetadataFilter metadataFilter : metadataFilters) {
            List<Metadata4Ref> metadataListByFilter = getMetadataListByFilter(metadataFilter);
            if (!CollectionUtils.isEmpty(metadataListByFilter)) {
                metadataList.addAll(metadataListByFilter);
            }
        }
        return metadataList;
    }

    public List<Metadata4Ref> getMetadataListByFilter(MetadataFilter metadataFilter) {
        List<Metadata4Ref> metadataList = getMetadataList(metadataFilter);
        if (CollectionUtils.isEmpty(metadataList) || metadataFilter == null) {
            return metadataList;
        }
        if (metadataFilter.getSuCodes() != null) {
            metadataList = metadataList.stream().filter(metadata4Ref
                            -> metadata4Ref.getServiceUnitInfo() != null
                            && metadata4Ref.getServiceUnitInfo().getServiceUnitCode() != null
                            // modify by sunhongfei01 sucode对比忽略大小写
                            && metadataFilter.getSuCodes().stream().anyMatch(
                            metadata4Ref.getServiceUnitInfo().getServiceUnitCode()::equalsIgnoreCase))
                    .collect(Collectors.toList());
        }

        if (metadataFilter.getBusinessObjectIds() != null) {
            metadataList = metadataList.stream().filter(metadata4Ref
                            -> metadata4Ref.getMetadata() != null
                            && metadata4Ref.getMetadata().getHeader() != null
                            && metadata4Ref.getMetadata().getHeader().getBizobjectID() != null
                            && metadataFilter.getBusinessObjectIds().stream().anyMatch(
                            metadata4Ref.getMetadata().getHeader().getBizobjectID()::equalsIgnoreCase))
                    .collect(Collectors.toList());
        }

        if (metadataFilter.getMetadataTypes() != null) {
            metadataList = metadataList.stream().filter(metadata4Ref
                    -> metadata4Ref.getMetadata() != null
                    && metadata4Ref.getMetadata().getHeader() != null
                    && metadata4Ref.getMetadata().getHeader().getType() != null
                    && metadataFilter.getMetadataTypes().contains(metadata4Ref.getMetadata().getHeader().getType())).collect(Collectors.toList());
        }

        if (metadataFilter.getProcessModes() != null) {
            metadataList = metadataList.stream().filter(metadata4Ref
                    -> metadata4Ref.getPackageHeader() != null
                    && metadata4Ref.getPackageHeader().getProcessMode() != null
                    && metadataFilter.getProcessModes().contains(metadata4Ref.getPackageHeader().getProcessMode())).collect(Collectors.toList());
        }

        if (metadataFilter.getMetadataNamespace() != null) {
            metadataList = metadataList.stream().filter(metadata4Ref
                    -> metadata4Ref.getMetadata() != null
                    && metadata4Ref.getMetadata().getHeader() != null
                    && metadata4Ref.getMetadata().getHeader().getNameSpace() != null
                    && metadata4Ref.getMetadata().getHeader().getNameSpace().equalsIgnoreCase(metadataFilter.getMetadataNamespace())).collect(Collectors.toList());
        }

        if (metadataFilter.getMetadataCode() != null) {
            metadataList = metadataList.stream().filter(metadata4Ref
                    -> metadata4Ref.getMetadata() != null
                    && metadata4Ref.getMetadata().getHeader() != null
                    && metadata4Ref.getMetadata().getHeader().getCode() != null
                    && metadata4Ref.getMetadata().getHeader().getCode().equalsIgnoreCase(metadataFilter.getMetadataCode())).collect(Collectors.toList());
        }
        return metadataList;
    }


    public List<Metadata4Ref> getMetadataList() {
        return getMetadataList(null);
    }

    public List<Metadata4Ref> getMetadataList(MetadataFilter metadataFilter) {
        List<Metadata4Ref> metadataList = new ArrayList<>();
        // 获取表中的元数据列表
        List<Metadata4Ref> mdpkgMetadataList = getMdpkgMetadataList(metadataFilter);
        if (!CollectionUtils.isEmpty(mdpkgMetadataList)) {
            metadataList.addAll(mdpkgMetadataList);
        }

        //获取运行时生成的元数据列表
        List<Metadata4Ref> generatedList = getGeneratedList(metadataFilter);
        if (!CollectionUtils.isEmpty(generatedList)) {
            metadataList.addAll(generatedList);
        }

        //获取运行定制的元数据列表
        List<Metadata4Ref> customizedList = getCustomizedList(metadataFilter);
        if (!CollectionUtils.isEmpty(customizedList)) {
            metadataList.addAll(customizedList);
        }

        return metadataList;
    }

    public List<Metadata4Ref> getGeneratedList(MetadataFilter metadataFilter) {
        if (metadataFilter != null && metadataFilter.getSourceType() != null && metadataFilter.getSourceType() != SourceTypeEnum.GENERATED) {
            return null;
        }
        return generatedRepoService.getAllRTGeneratedMetadata();
    }

    public List<Metadata4Ref> getMdpkgMetadataList(MetadataFilter metadataFilter) {
        if (metadataFilter != null && metadataFilter.getSourceType() != null && metadataFilter.getSourceType() != SourceTypeEnum.MDPKG) {
            return null;
        }
        return mdRtRepoService.getAllPkgMetadata(metadataFilter);
    }

    public List<Metadata4Ref> getCustomizedList(MetadataFilter metadataFilter) {
        return null;
    }

    public void removeCacheByMetadataIds(List<String> metadataIds) {
        if (!CollectionUtils.isEmpty(metadataIds)) {
            for (String metadataId : metadataIds) {
                RemoveDistCache(metadataId);
                RemoveRtDistCache(metadataId);
            }
        }
    }

    public void RemoveDistCache(String id) {
        MetadataDistCacheManager.remove(RtCacheHandler.getMetadataCacheKey(id, ""));

        LanguageService laguageService = SpringBeanUtils.getBean(LanguageService.class);
        List<EcpLanguage> ecpLanguages = laguageService.getEnabledLanguages();
        for (EcpLanguage ecpLanguage : ecpLanguages) {
            MetadataDistCacheManager.remove(RtCacheHandler.getMetadataCacheKey(id, ecpLanguage.getCode()));
        }
    }

    public void RemoveRtDistCache(String id) {
        MetadataRtDistCache.remove(RtCacheHandler.getMetadataCacheKey(id, ""));

        LanguageService laguageService = SpringBeanUtils.getBean(LanguageService.class);
        List<EcpLanguage> ecpLanguages = laguageService.getEnabledLanguages();
        for (EcpLanguage ecpLanguage : ecpLanguages) {
            MetadataRtDistCache.remove(RtCacheHandler.getMetadataCacheKey(id, ecpLanguage.getCode()));
        }
    }

    protected GspMetadata getI18nMetadata(GspMetadata metadata, String language) {
        I18nResourceRTService i18nResourceRTService = I18nResourceRTUtils.getI18nResourceRTService();
        if (i18nResourceRTService == null) {
            return metadata;
        }
        GspMetadata i18nMetadata;
        try {
            language = StringUtils.isEmpty(language) ? RuntimeContext.getLanguage() : language;
            List<I18nResource> resources = i18nResourceRTService.getI18nResource(metadata, language);
            MetadataI18nService service = I18nManagerHelper.getInstance().getI18nManager(metadata.getHeader().getType());
            if (service != null && resources != null && resources.size() > 0) {
                i18nMetadata = service.merge(metadata, resources);
                return i18nMetadata;
            }
        } catch (Exception e) {
            //TODO 表单强制获取资源项，获取不到时会报错，异常太多，暂时catch住
        }
        return metadata;
    }

    protected GspMetadata getMetadataFromDb(String metadataId) {
        return null;
    }

    protected GspMetadata getMetadataFromCache(String metadataId, boolean isI18n) {
        return null;
    }

    protected void putMetadataToCache(String metadataId, GspMetadata metadata, boolean isI18n) {
        return;
    }

    protected ProcessMode getProcessModeByMetadataId(String metadataId) {
        Metadata4Ref metadata4Ref = mdRtRepoService.getPkgMetadataByMetadataId(metadataId);
        if (metadata4Ref == null || metadata4Ref.getPackageHeader() == null) {
            log.info("获取元数据包信息为空：{}", metadataId);
            return null;
        }
        return metadata4Ref.getPackageHeader().getProcessMode();
    }

    protected void fireMetadataDeletingEvent(GspMetadata metadata) {
        getMetadataRtEventBroker().fireMetadataDeletingEvent(new MetadataRtEventArgs(metadata, EnvironmentContext.env));
    }

    protected void fireMetadataDeletedEvent(GspMetadata metadata) {
        getMetadataRtEventBroker().fireMetadataDeletedEvent(new MetadataRtEventArgs(metadata, EnvironmentContext.env));
    }

    protected void fireMetadataSavingEvent(GspMetadata metadata, ProcessMode processMode) {
        getMetadataRtEventBroker().fireMetadataSavingEvent(new MetadataRtEventArgs(metadata, processMode, EnvironmentContext.env));
    }

    protected void fireMetadataSavedEvent(GspMetadata metadata, ProcessMode processMode) {
        getMetadataRtEventBroker().fireMetadataSavedEvent(new MetadataRtEventArgs(metadata, processMode, EnvironmentContext.env));
    }

    protected void fireMetadataAchievedEvent(GspMetadata metadata) {
        getMetadataRtEventBroker().fireMetadataAchievedEvent(new MetadataRtEventArgs(metadata, EnvironmentContext.env));
    }

    protected void fireGeneratedMetadataSavedEvent(GspMetadata metadata) {
        getMetadataRtEventBroker().fireGeneratedMetadataSavingEvent(new MetadataRtEventArgs(metadata, EnvironmentContext.env));
    }

    protected void fireGeneratedMetadataSavingEvnet(GspMetadata metadata) {
        getMetadataRtEventBroker().fireGeneratedMetadataSavedEvent(new MetadataRtEventArgs(metadata, EnvironmentContext.env));
    }

    protected void fireMdPkgChangedEvent(MetadataPackage metadataPackage) {
        MdPkgChangedEventBroker broker = SpringBeanUtils.getBean(MdPkgChangedEventBroker.class);
        MdPkgChangedArgs args = new MdPkgChangedArgs();
        args.setMetadataPackage(metadataPackage);
        broker.fireMdPkgChangedEvent(args);
    }
}
